/**
* Copyright (C) 2003-2008 eXo Platform SAS.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see<http://www.gnu.org/licenses/>.
*/
package org.etk.core.rest.impl.provider;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.util.ByteArrayDataSource;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.Provider;
import org.etk.core.rest.RequestHandler;
import org.etk.core.rest.impl.ApplicationContext;
import org.etk.core.rest.impl.ApplicationContextImpl;
import org.etk.core.rest.provider.EntityProvider;
@Provider
public class DataSourceEntityProvider implements EntityProvider<DataSource> {
/**
* {@inheritDoc}
*/
public boolean isReadable(Class<?> type,
Type genericType,
Annotation[] annotations,
MediaType mediaType) {
return type == DataSource.class;
}
/**
* {@inheritDoc}
*/
public DataSource readFrom(Class<DataSource> type,
Type genericType,
Annotation[] annotations,
MediaType mediaType,
MultivaluedMap<String, String> httpHeaders,
InputStream entityStream) throws IOException {
String m = mediaType != null ? mediaType.toString() : null;
return createDataSource(entityStream, m);
}
/**
* {@inheritDoc}
*/
public long getSize(DataSource t,
Class<?> type,
Type genericType,
Annotation[] annotations,
MediaType mediaType) {
return -1;
}
/**
* {@inheritDoc}
*/
public boolean isWriteable(Class<?> type,
Type genericType,
Annotation[] annotations,
MediaType mediaType) {
return DataSource.class.isAssignableFrom(type);
}
/**
* {@inheritDoc}
*/
public void writeTo(DataSource t,
Class<?> type,
Type genericType,
Annotation[] annotations,
MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders,
OutputStream entityStream) throws IOException {
InputStream in = t.getInputStream();
try {
IOHelper.write(in, entityStream);
} finally {
in.close();
}
}
/**
* Create DataSource instance dependent entity size. If entity has size less
* then <tt>MAX_BUFFER_SIZE</tt> then {@link ByteArrayDataSource} will be
* created otherwise {@link MimeFileDataSource} will be created.
*
* @param entityStream the {@link InputStream} of the HTTP entity
* @param mimeType media type of data, HTTP header 'Content-type'
* @return See {@link DataSource}
* @throws IOException if any i/o errors occurs
*/
private static DataSource createDataSource(InputStream entityStream, String mimeType) throws IOException {
boolean overflow = false;
byte[] buffer = new byte[8192];
ApplicationContext context = ApplicationContextImpl.getCurrent();
int bufferSize = (Integer) context.getAttributes().get(RequestHandler.WS_RS_BUFFER_SIZE);
ByteArrayOutputStream bout = new ByteArrayOutputStream(bufferSize);
int bytes = -1;
while ((bytes = entityStream.read(buffer)) != -1) {
bout.write(buffer, 0, bytes);
if (bout.size() > bufferSize) {
overflow = true;
break;
}
}
if (!overflow)
// small data , use bytes
return new ByteArrayDataSource(bout.toByteArray(), mimeType);
// large data, use file
final File file = File.createTempFile("datasource", "tmp");
OutputStream fout = new FileOutputStream(file);
// copy data from byte array in file
bout.writeTo(fout);
while ((bytes = entityStream.read(buffer)) != -1)
fout.write(buffer, 0, bytes);
fout.close();
return new MimeFileDataSource(file, mimeType);
}
/**
* FileDataSource with preset media type.
*/
static class MimeFileDataSource extends FileDataSource {
/**
* Media type of the data.
*/
private final String mimeType;
/**
* @param file file
* @param mimeType media type
*/
public MimeFileDataSource(File file, String mimeType) {
super(file);
this.mimeType = mimeType;
}
/**
* Try remove file when object destroyed. {@inheritDoc}
*/
@Override
protected void finalize() throws Throwable {
super.finalize();
File file = getFile();
if (file.exists())
file.delete();
}
/**
* {@inheritDoc}
*/
@Override
public String getContentType() {
return mimeType;
}
}
}